package com.cmc6.request.aop;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.jwt.JWT;
import com.cmc6.common.config.security.SecurityConfig;
import com.cmc6.common.constant.BaseConstant;
import com.cmc6.common.util.ApiResult;
import com.cmc6.common.util.IpUtil;
import com.cmc6.common.util.RequestUtil;
import com.cmc6.common.util.UserUtil;
import com.cmc6.request.model.entity.RequestDO;
import com.cmc6.request.service.RequestService;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

@Aspect
@Component
public class RequestAop {

    @Resource
    RequestService requestService;
    @Resource
    HttpServletRequest request;

    /**
     * 切入点
     */
    @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
    public void pointcut() {
    }

    @SneakyThrows
    @Around("pointcut() && @annotation(apiOperation)")
    public Object around(ProceedingJoinPoint proceedingJoinPoint, ApiOperation apiOperation) {

        long timeNumber = System.currentTimeMillis();

        Object object = proceedingJoinPoint.proceed(); // 执行方法

        // 备注：如果执行方法时抛出了异常，那么代码不会往下执行

        timeNumber = System.currentTimeMillis() - timeNumber; // 耗时（毫秒）

        if (timeNumber == 0) {
            return object;
        }

        String uri = request.getRequestURI();

        // 这个路径不需要记录到数据库
        if (uri.equalsIgnoreCase(SecurityConfig.FILE_PUBLIC_DOWNLOAD_URL)) {
            return object;
        }

        String time = DateUtil.formatBetween(timeNumber, BetweenFormatter.Level.MILLISECOND); // 耗时（字符串）

        RequestDO entity = new RequestDO();

        Date date = new Date();
        Long userIdSafe = UserUtil.getCurrentUserIdSafe();
        entity.setCreateId(userIdSafe);
        entity.setCreateTime(date);
        entity.setUpdateId(userIdSafe);
        entity.setUpdateTime(date);

        entity.setUri(uri);
        entity.setTime(time);
        entity.setTimeNumber(timeNumber);
        entity.setName(apiOperation.value()); // 接口的描述
        entity.setCategory(RequestUtil.getRequestCategoryEnum()); // 类别：1 H5（网页端） 2 APP（移动端） 3 PC（桌面程序） 4 微信小程序
        entity.setIp(ServletUtil.getClientIP(request));
        entity.setRegion(IpUtil.getRegion(entity.getIp()));

        // 登录时需要额外处理来获取 用户id，备注：这里都必须以 /login开头才行
        if (uri.startsWith("/login") && !uri.contains("/sendCode")) {
            ApiResult<String> apiResult = (ApiResult)object;
            JWT jwtOf = JWT.of(apiResult.getData().replace(BaseConstant.JWT_PREFIX, ""));
            Long userId = Convert.toLong(jwtOf.getPayload("userId"));
            entity.setCreateId(userId);
            entity.setUpdateId(userId);
        }

        // 存库
        ThreadUtil.execute(() -> requestService.save(entity));

        return object;
    }

}
